/**
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { SetupContext } from 'vue';
import { TooltipPlacement, TooltipProps } from '../tooltip.props';
import { RectPosition, TooltipPosition } from './types';

export function useCalculatePosition(props: TooltipProps, context: SetupContext) {
    const space = 6;

    function calculateArrowPosition(
        placementAndAlignment: TooltipPlacement,
        hostBound: DOMRect,
        tooltipPosition: RectPosition,
        tooltipContentBound: DOMRect,
        arrowBound: DOMRect
    ): RectPosition {
        const placementAndAlignmentArray = placementAndAlignment.split('-');
        const placement = placementAndAlignmentArray[0];
        const alignment = placementAndAlignmentArray[1] || 'middle';

        const offsetX = ['top', 'bottom'].includes(placement)
            ? alignment === 'middle'
                ? (tooltipContentBound.width - arrowBound.width) / 2
                : alignment === 'right'
                ? tooltipContentBound.width - arrowBound.width - space
                : space
            : 0;

        const offsetY = ['left', 'right'].includes(placement)
            ? alignment === 'middle'
                ? (tooltipContentBound.height - arrowBound.height) / 2
                : alignment === 'bottom'
                ? tooltipContentBound.height - arrowBound.height - space
                : space
            : 0;

        const arrowLeft = placement === 'left' ? tooltipContentBound.width + arrowBound.width : 0;
        const arrowTop = placement === 'top' ? tooltipContentBound.height + arrowBound.height : 0;

        return { left: arrowLeft + offsetX, top: arrowTop + offsetY, right: 0 };
    }

    function calculateTooltipPosition(
        placementAndAlignment: TooltipPlacement,
        hostBound: DOMRect,
        tooltipBound: DOMRect,
        tooltipContentBound: DOMRect,
        arrowBound: DOMRect
    ) {
        const placementAndAlignmentArray = placementAndAlignment.split('-');
        const placement = placementAndAlignmentArray[0];
        const alignment = placementAndAlignmentArray[1] || 'middle';
        const horizontalMarginSpace = (tooltipBound.width - tooltipContentBound.width) / 2;
        const verticalMarginSpace = (tooltipBound.height - tooltipContentBound.height) / 2;
        const originalPositionX = placement === 'right' ? hostBound.right : hostBound.left;
        const originalPositionY = placement === 'bottom' ? hostBound.bottom : hostBound.top;

        const offsetY =
            placement === 'top'
                ? 0 - verticalMarginSpace - tooltipContentBound.height - arrowBound.height
                : placement === 'bottom'
                ? 0 - verticalMarginSpace + arrowBound.height
                : 0;

        const verticalAlignmentOffset = ['left', 'right'].includes(placement)
            ? alignment === 'middle'
                ? (hostBound.height - tooltipContentBound.height) / 2
                : alignment === 'bottom'
                ? hostBound.height - tooltipContentBound.height
                : 0
            : 0;

        const offsetX =
            placement === 'left'
                ? 0 - horizontalMarginSpace - tooltipContentBound.width - arrowBound.width
                : placement === 'right'
                ? 0 - horizontalMarginSpace + arrowBound.width
                : 0;

        const horizontalAlignmentOffset = ['top', 'bottom'].includes(placement)
            ? alignment === 'middle'
                ? (hostBound.width - tooltipContentBound.width) / 2
                : alignment === 'right'
                ? hostBound.width - tooltipContentBound.width
                : 0
            : 0;

        const top = originalPositionY + offsetY + verticalAlignmentOffset;
        const left = originalPositionX + offsetX + horizontalAlignmentOffset;
        return { left, top };
    }

    function calculate(
        placementAndAlignment: TooltipPlacement,
        hostBound: DOMRect,
        tooltipBound: DOMRect,
        tooltipContentBound: DOMRect,
        arrowBound: DOMRect
    ): TooltipPosition {
        const tooltip = calculateTooltipPosition(placementAndAlignment, hostBound, tooltipBound, tooltipContentBound, arrowBound);
        const arrow = calculateArrowPosition(placementAndAlignment, hostBound, tooltipBound, tooltipContentBound, arrowBound);
        return { arrow, tooltip };
    }

    return { calculate };
}
